/* @flow */

import Logger from 'jitsi-meet-logger';
import { CONFERENCE_WILL_JOIN } from '../base/conference';
import {
    SIP_GW_AVAILABILITY_CHANGED,
    SIP_GW_INVITE_ROOMS
} from './actionTypes';
import {
    JitsiConferenceEvents,
    JitsiSIPVideoGWStatus
} from '../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../base/redux';
import {
    showErrorNotification,
    showNotification,
    showWarningNotification
} from '../notifications';

const logger = Logger.getLogger(__filename);

/**
 * Middleware that captures conference video sip gw events and stores
 * the global sip gw availability in redux or show appropriate notification
 * for sip gw sessions.
 * Captures invitation actions that create sip gw sessions or display
 * appropriate error/warning notifications.
 *
 * @param {Store} store - The redux store.
 * @returns {Function}
 */
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
    const result = next(action);

    switch (action.type) {
    case CONFERENCE_WILL_JOIN: {
        const conference = getState()['features/base/conference'].joining;

        conference.on(
            JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,
            (...args) => dispatch(_availabilityChanged(...args)));
        conference.on(
            JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,
            event => {
                const toDispatch = _sessionStateChanged(event);

                // sessionStateChanged can decide there is nothing to dispatch
                if (toDispatch) {
                    dispatch(toDispatch);
                }
            });

        break;
    }
    case SIP_GW_INVITE_ROOMS: {
        const { status } = getState()['features/videosipgw'];

        if (status === JitsiSIPVideoGWStatus.STATUS_UNDEFINED) {
            dispatch(showErrorNotification({
                descriptionKey: 'recording.unavailable',
                descriptionArguments: {
                    serviceName: '$t(videoSIPGW.serviceName)'
                },
                titleKey: 'videoSIPGW.unavailableTitle'
            }));

            return;
        } else if (status === JitsiSIPVideoGWStatus.STATUS_BUSY) {
            dispatch(showWarningNotification({
                descriptionKey: 'videoSIPGW.busy',
                titleKey: 'videoSIPGW.busyTitle'
            }));

            return;
        } else if (status !== JitsiSIPVideoGWStatus.STATUS_AVAILABLE) {
            logger.error(`Unknown sip videogw status ${status}`);

            return;
        }

        for (const room of action.rooms) {
            const { id: sipAddress, name: displayName } = room;

            if (sipAddress && displayName) {
                const newSession = action.conference
                    .createVideoSIPGWSession(sipAddress, displayName);

                if (newSession instanceof Error) {
                    const e = newSession;

                    if (e) {
                        switch (e.message) {
                        case JitsiSIPVideoGWStatus.ERROR_NO_CONNECTION: {
                            dispatch(showErrorNotification({
                                descriptionKey: 'videoSIPGW.errorInvite',
                                titleKey: 'videoSIPGW.errorInviteTitle'
                            }));

                            return;
                        }
                        case JitsiSIPVideoGWStatus.ERROR_SESSION_EXISTS: {
                            dispatch(showWarningNotification({
                                titleKey: 'videoSIPGW.errorAlreadyInvited',
                                titleArguments: { displayName }
                            }));

                            return;
                        }
                        }
                    }
                    logger.error(
                        'Unknown error trying to create sip videogw session',
                        e);

                    return;
                }

                newSession.start();
            } else {
                logger.error(`No display name or sip number for ${
                    JSON.stringify(room)}`);
            }
        }
    }
    }

    return result;
});

/**
 * Signals that sip gw availability had changed.
 *
 * @param {string} status - The new status of the service.
 * @returns {{
 *     type: SIP_GW_AVAILABILITY_CHANGED,
 *     status: string
 * }}
 * @private
 */
function _availabilityChanged(status: string) {
    return {
        type: SIP_GW_AVAILABILITY_CHANGED,
        status
    };
}

/**
 * Signals that a session we created has a change in its status.
 *
 * @param {string} event - The event describing the session state change.
 * @returns {{
 *     type: SHOW_NOTIFICATION
 * }}|null
 * @private
 */
function _sessionStateChanged(
        event: Object) {
    switch (event.newState) {
    case JitsiSIPVideoGWStatus.STATE_PENDING: {
        return showNotification({
            titleKey: 'videoSIPGW.pending',
            titleArguments: {
                displayName: event.displayName
            }
        }, 2000);
    }
    case JitsiSIPVideoGWStatus.STATE_FAILED: {
        return showErrorNotification({
            titleKey: 'videoSIPGW.errorInviteFailedTitle',
            titleArguments: {
                displayName: event.displayName
            },
            descriptionKey: 'videoSIPGW.errorInviteFailed'
        });
    }
    }

    // nothing to show
    return null;
}
